home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 2.toast / pc / sample code / quicktime / quicktimeintro / wiredsprites / common files / imagecompressionutilities.c < prev    next >
Encoding:
Text File  |  2000-10-06  |  22.5 KB  |  767 lines

  1. //////////
  2. //
  3. //    File:        ImageCompressionUtilities.c
  4. //
  5. //    Contains:    Image Compression Utilities.
  6. //
  7. //    Written by:    Peter Hoddie, Sean Allen, Chris Flick
  8. //    Revised by:    Tim Monroe
  9. //
  10. //    Copyright:    © 1998 by Apple Computer, Inc., all rights reserved.
  11. //
  12. //    Change History (most recent first):
  13. //
  14. //       <6>         03/17/00    rtm        moved some things to ImageCompressionUtilities.h; made some changes for Carbon
  15. //       <5>         02/25/00    rtm        changed pascal keyword to PASCAL_RTN, for Windows compatibility
  16. //       <4>         12/16/98    rtm        removed orphaned prototype for compressTransparentRLEwithHitTesting
  17. //       <3>         05/28/98    rtm        added some typecasting to minimize MSDev compiler warnings
  18. //       <2>         03/22/98    rtm        made changes to RecompressPictureFileWithTransparency, as per Chris' fixes
  19. //       <1>         03/27/98    rtm        existing file
  20. //
  21. //////////
  22.  
  23.  
  24. //////////
  25. //
  26. // header files
  27. //
  28. //////////
  29.  
  30. #ifndef __IMAGECOMPRESSIONUTILITIES__
  31. #include "ImageCompressionUtilities.h"
  32. #endif
  33.  
  34.  
  35. // PICT to compressed image conversion
  36.  
  37. //    Given a QuickDraw picture, extract QuickTime compressed image data and description, if any.
  38. //
  39. //    It does this by creating a temporary CGrafPort, installing a QuickDraw bottleneck
  40. //    routine for the StdPix call, and then drawing the picture. Since this routine will
  41. //    be called whenever QuickTime compressed image data is encountered, it can
  42. //    stash away any found compressed data and description. On DrawPicture's return, the
  43. //    stashed data and description is retrieved and returned to the caller.
  44. //
  45. //    Worth noting in this utility is definition of the extractPictRecord. This is a 
  46. //    structure consisting of a CGrafPort structure followed by fields for a handle to 
  47. //    image data and an ImageDescription. This layout allows ExtractCompressData to open
  48. //    a CGrafPort using the embedded CGrafPort field, and set this as the current port. 
  49. //    Then, in the StdPix routine extractStdPix, the current port can be retrieved and 
  50. //    cast to a pointer to an extractPictRecord to get access to the other fields.
  51. //
  52.  
  53. #if 0
  54. OSErr ExtractCompressData ( PicHandle thePict, Handle *dataOut, ImageDescriptionHandle *idh )
  55. {
  56.     OSErr                err = noErr;
  57.     extractPictRecord     state;
  58.     CQDProcs             procs;
  59.     GrafPtr             savePort;
  60.     Rect                 bounds;
  61.  
  62.     if ( dataOut )
  63.         *dataOut = nil;
  64.     if ( idh )
  65.         *idh = nil;
  66.  
  67.     GetPort( &savePort );
  68.  
  69.     OpenCPort( &state.tempPort );
  70.     SetStdCProcs( &procs );
  71.     procs.newProc1 = (UniversalProcPtr)NewStdPixProc(extractStdPix);
  72.     state.tempPort.grafProcs = &procs;
  73.  
  74.     state.data = nil;
  75.     state.idh = nil;
  76.  
  77.     MacSetPort( (GrafPtr)&state.tempPort );
  78.     HidePen();
  79.  
  80.     bounds = (**thePict).picFrame;
  81.     DrawPicture(thePict, &bounds);    
  82.  
  83.     MacSetPort( savePort );
  84.     CloseCPort( &state.tempPort );
  85.  
  86.     DisposeRoutineDescriptor( procs.newProc1 );
  87.     
  88.     *dataOut    = state.data;
  89.     *idh        = state.idh;
  90.  
  91.     return err;
  92. }
  93. #endif
  94.  
  95.  
  96. PASCAL_RTN void extractStdPix ( PixMap *src, Rect *srcRect, MatrixRecord *matrix, short mode, RgnHandle mask, PixMap *matte, Rect *matteRect, short flags )
  97. {
  98. #if TARGET_OS_MAC
  99. #pragma unused(srcRect,matrix,mode,mask,matte,matteRect,flags)
  100. #endif
  101.     extractPictRecord    *state;
  102.  
  103.     GetPort( (GrafPtr *)&state );
  104.  
  105.     if  ( state->idh == nil ) {
  106.         ImageDescriptionHandle    desc;
  107.         Ptr                     data;
  108.         long                    bufferSize;
  109.  
  110.         if ( GetCompressedPixMapInfo(src, &desc, &data, &bufferSize, nil, nil) == noErr ) {
  111.             state->idh = desc;
  112.             HandToHand( (Handle *)&state->idh );
  113.             PtrToHand( data, &state->data, bufferSize );
  114.         }
  115.     }
  116. }
  117.  
  118.  
  119. static ImageDescriptionHandle createImageDescription ( CodecType cType, PixMapHandle pixmap )
  120. {
  121.     ImageDescriptionHandle    desc = nil;
  122.     
  123.     if ( ( desc = (ImageDescription **)NewHandleClear(sizeof(ImageDescription)) ) != nil ) {
  124.         ImageDescription     *dp = *desc;
  125.         Rect                bounds = (**pixmap).bounds;
  126.  
  127.         dp->idSize             = sizeof(ImageDescription);
  128.         dp->cType             = cType;    
  129.         dp->spatialQuality     = codecNormalQuality;
  130.         dp->width            = bounds.right - bounds.left;
  131.         dp->height             = bounds.bottom - bounds.top;
  132.         dp->hRes             = 72L << 16;
  133.         dp->vRes             = 72L << 16;
  134.         dp->dataSize         = ((**pixmap).rowBytes & 0x3fff) * dp->height;
  135.         dp->depth             = (**pixmap).pixelSize;
  136.         dp->clutID             = -1;
  137.         
  138.         if ( SetImageDescriptionCTable( desc, (**pixmap).pmTable ) ) {
  139.             DisposeHandle( (Handle) desc );
  140.             desc = nil;
  141.         }
  142.     }
  143.     return desc;
  144. }
  145.  
  146. PASCAL_RTN void noDitherBitsProc (BitMap *srcBits, Rect *srcRect, Rect *dstRect, short mode, RgnHandle maskRgn)
  147. {
  148.     mode &= ~ditherCopy;
  149.     StdBits(srcBits, srcRect, dstRect, mode, maskRgn);
  150. }
  151.  
  152. //    DrawPictureNoDither is used to draw a QuickDraw picture but to turn convert any
  153. //    use of ditherCopy graphics modes to graphics modes that don't use ditherCopy. It
  154. //    only performs this with the stdbits bottleneck routine. Since ditherCopy is simply
  155. //    ORed in with other graphics modes, the replaced bottleneck routine only needs to
  156. //    AND off the ditherCopy flag.
  157.  
  158. void DrawPictureNoDither(PicHandle pic, const Rect *bounds)
  159. {        
  160.     CQDProcs        procs;
  161.     GrafPtr            savePort;
  162.     CQDProcsPtr        saveProcs;
  163.  
  164.     GetPort(&savePort);
  165.     saveProcs = GetPortGrafProcs(savePort);
  166.     SetStdCProcs( &procs );
  167.  
  168.     procs.bitsProc = NewQDBitsUPP(noDitherBitsProc);
  169.     
  170.     SetPortGrafProcs((CGrafPtr)savePort, &procs);
  171.  
  172.     DrawPicture(pic, bounds);
  173.  
  174.     SetPortGrafProcs((CGrafPtr)savePort, saveProcs);
  175.  
  176.     DisposeQDBitsUPP( procs.bitsProc );
  177. }
  178.  
  179.  
  180. //
  181. // The following is a routine that can be used to clean up the colors in a picture
  182. // before being compressed with the Animation compressor in 16-bits at codecNormal
  183. // quality. The QuickTime Animation compressor can operate in both a lossless and
  184. // lossy manner. This routine is meant to help when compressing in a lossy manner.
  185. //
  186. // By clean up, what's meant is the forcing of any colors that are sufficiently close
  187. // to white to colors that are not as close. Since the Animation compressor will
  188. // perform threshholding of the image's colors when codecNormal quality is specified,
  189. // without this preprocessing, colors very close to white can be mapped to white
  190. // in the compression. If white was chosen as the key color, pixels that are
  191. // close to white could possibly become transparent as well.
  192. //
  193. // While not used by other routines in this file, prepareFor16BitCompress is provided
  194. // as an example of how this might be done.
  195. //
  196. // Note that with codecLossless quality, there is no remapping of colors so this
  197. // step is unnecessary.
  198. //
  199.  
  200. OSErr prepareFor16BitCompress(PicHandle *pic)
  201. {
  202.     PicHandle                newPicture = nil;
  203.     Rect                    r;
  204.     GWorldPtr                gw = nil;
  205.     CGrafPtr                savePort;
  206.     GDHandle                saveGD;
  207.     short                    rowBytes;
  208.     Ptr                        baseAddr;
  209.     long                    w, h;
  210.     PixMapHandle            pm;
  211.     OSErr                    err = noErr;
  212.  
  213.     GetGWorld(&savePort, &saveGD);
  214.  
  215.     r = (***pic).picFrame;
  216.     MacOffsetRect(&r, (short)-r.left, (short)-r.top);
  217.  
  218.     err = NewGWorld(&gw, 32, &r, nil, nil, useTempMem);
  219.     if (err) {
  220.         err = NewGWorld(&gw, 32, &r, nil, nil, 0);
  221.         if (err) goto bail;
  222.     }
  223.  
  224.     pm = GetGWorldPixMap(gw);
  225.     LockPixels(pm);
  226.     SetGWorld(gw, nil);
  227.     EraseRect(&r);
  228.  
  229.     DrawPicture(*pic, &r);
  230.  
  231.     baseAddr = GetPixBaseAddr(pm);
  232.     rowBytes = (**pm).rowBytes & 0x3fff;
  233.     for (h=0; h<r.bottom; h++) {
  234.         long *pixelPtr = (long *)baseAddr;
  235.  
  236.         for (w=0; w<r.right; w++, pixelPtr++) {
  237.             UInt8 r, g, b, a;
  238.             long pixel = *pixelPtr;
  239.  
  240.             if ((pixel & 0x0ffffff) == 0x00ffffff)        // pure white
  241.                 continue;
  242.  
  243.             a = (pixel >> 24) & 0x0ff;
  244.             r = (pixel >> 16) & 0x0ff;
  245.             g = (pixel >>  8) & 0x0ff;
  246.             b = (pixel >>  0) & 0x0ff;
  247.             if ((r > kThreshold) && (g > kThreshold) && (b > kThreshold)) {
  248.                 r = g = b = kThreshold;
  249.                 *pixelPtr = (a << 24) | (kThreshold << 16) | (kThreshold << 8) | (kThreshold << 0);
  250.             }
  251.         }
  252.  
  253.         baseAddr += rowBytes;
  254.     }
  255.  
  256.     newPicture = OpenPicture(&r);
  257.     CopyBits((BitMapPtr)*GetGWorldPixMap(gw),
  258.              (BitMapPtr)*GetGWorldPixMap(gw),
  259.              &r,
  260.              &r,
  261.              ditherCopy,
  262.              NULL);
  263.              
  264.     ClosePicture();
  265.     UnlockPixels(pm);
  266.  
  267. bail:
  268.     if (gw)
  269.         DisposeGWorld(gw);
  270.  
  271.     if (err == noErr) {
  272.         if (newPicture) {
  273.             KillPicture(*pic);
  274.             *pic = newPicture;
  275.         }
  276.     }
  277.  
  278.     SetGWorld(savePort, saveGD);
  279.  
  280.     return err;
  281. }
  282.  
  283.  
  284. /*
  285.     ---------------- Callback based routines for compressing with hittesting and transparency ----------------
  286.  */
  287.  
  288. /*
  289.     RecompressWithTransparencyFromProc
  290.     
  291.     This is a routine either called indirectly through RecompressCompressedImageWithTransparency, 
  292.     RecompressPictureWithTransparency, or RecompressPictureFileWithTransparency or called directly.
  293.     It takes a callback procedure which is responsible for returning the dimensions of the
  294.     area of some type of drawable entity and for actually drawing that entity.
  295.     
  296.         includeHitTesting        TRUE if hit testing data should be added to the compressed data
  297.         keyColor                A RGBColor that should be used as the transparency color. Pass nil
  298.                                 if the image doesn't have transparent portions.
  299.         hitTestRegion            A RgnHandle specifying an area that is to be used as the hit test
  300.                                 area. If you pass this, you must also set includeHitTesting to TRUE.
  301.                                 This is optional as the callback procedure can perform drawing
  302.                                 itself of the hit test area which is often suitable when both the
  303.                                 image and hit test area were painted in a drawing program.
  304.         idh                        Returned ImageDescriptionHandle for the compressed image data
  305.         imageData                Returned Handle to the compressed image data
  306.  
  307.  */
  308.  
  309. OSErr RecompressWithTransparencyFromProc( CompressDrawProc drawProc, void * drawProcRefcon, 
  310.                                                     Boolean includeHitTesting,
  311.                                                     RGBColor *keyColor, 
  312.                                                     RgnHandle hitTestRegion,
  313.                                                     ImageDescriptionHandle *idh, Handle * imageData )
  314. {
  315.     OSErr                         err = noErr;
  316.     Rect                        bounds;
  317.     CGrafPtr                    savePort;
  318.     GDHandle                    saveDevice;
  319.     GWorldPtr                    gwImage = nil;        // always used
  320.     GWorldPtr                    gwPrev = nil;        // used if compressing with transparency (via keycolor)
  321.     GWorldPtr                    gwMap = nil;        // used if compressing with hittesting data
  322.     ImageDescriptionHandle        desc = nil;            // resulting image description
  323.     ImageDescriptionHandle        gwMapDesc = nil;
  324.     ImageSequence                seq = 0;            // compress sequence
  325.     ImageSequenceDataSource        mapSource = 0L;
  326.     Ptr                            data = nil;
  327.     long                         dataSize;
  328.     UInt8                         similarity;
  329.     Boolean                        includeTransparency = false;
  330.     RGBColor                    saveBackColor;
  331.         
  332.     GetGWorld( &savePort, &saveDevice );
  333.     
  334.     if( !drawProc || !idh || !imageData ){
  335.         err = paramErr;
  336.         goto bail;
  337.     }
  338.     
  339.     // tell callback that it should initialize any storage it needs
  340.     err = drawProc( kRecoProcInitMsg, nil, nil, 0, drawProcRefcon );
  341.     if(err) goto bail;
  342.     
  343.     // determine bounds to use for compression
  344.     err = drawProc( kRecoProcGetBoundsMsg, &bounds, nil, 0, drawProcRefcon );
  345.     if(err) goto bail;
  346.     
  347.     err = QTNewGWorld(&gwImage, kCompressDepth, &bounds, nil, nil, kICMTempThenAppMemory);
  348.     if(err) goto bail;
  349.  
  350.     if( keyColor ) {
  351.         includeTransparency = true;
  352.     }
  353.     
  354.     // Include hit testing? If so, we need a previous buffer and an 8-bit GWorld for the mask data
  355.     if( includeHitTesting ) {
  356.         err = QTNewGWorld(&gwPrev, kCompressDepth, &bounds, nil, nil, kICMTempThenAppMemory);
  357.         if(err) goto bail;
  358.  
  359.         err = QTNewGWorld(&gwMap, 8, &bounds, nil, nil, kICMTempThenAppMemory);
  360.         if(err) goto bail;
  361.     }
  362.     
  363.     LockPixels( GetGWorldPixMap(gwImage) );
  364.     
  365.     if( gwPrev )
  366.         LockPixels( GetGWorldPixMap(gwPrev) );
  367.     
  368.     if( gwMap )
  369.         LockPixels( GetGWorldPixMap(gwMap) );
  370.     
  371.     if(gwPrev) {
  372.         SetGWorld( gwPrev, nil );
  373.         ClipRect( &bounds );
  374.         
  375.         GetBackColor( &saveBackColor );
  376.         if( keyColor )
  377.             RGBBackColor( keyColor );
  378.         
  379.             EraseRect( &bounds );
  380.             
  381.         RGBBackColor( &saveBackColor );
  382.     }
  383.     
  384.     if( gwMap ) {
  385.         SetGWorld( gwMap, nil );
  386.         
  387.         EraseRect( &bounds );            // paint background white
  388.  
  389.         err = drawProc( kRecoProcDrawMsg, &bounds, gwMap, kRecoProcHitTestingImageType, drawProcRefcon );
  390.         if(err) goto bail;
  391.         
  392.         if( hitTestRegion ) {
  393.             RGBColor blackRGB;
  394.             
  395.             blackRGB.red = blackRGB.green = blackRGB.blue = 0;
  396.             
  397.             RGBForeColor( &blackRGB );
  398.             MacPaintRgn( hitTestRegion );
  399.         }
  400.  
  401.         gwMapDesc = createImageDescription(kRawCodecType, GetGWorldPixMap(gwMap));
  402.         err = MemError();
  403.         if(err) goto bail;
  404.     }
  405.     
  406.     SetGWorld( gwImage, nil );
  407.     ClipRect( &bounds );
  408.     EraseRect( &bounds );
  409.     
  410.     desc = (ImageDescriptionHandle) NewHandle(sizeof(ImageDescription));
  411.  
  412.  
  413.     // NOTE: We pass codecLosslessQuality so that the key color if any is matched exactly. This avoids colors within
  414.     // some threshhold different from the key color being taken as equivalent to the key color. Alternatively, we
  415.     // could perform some threshhold processing on the source image's pixels and pass codecNormalQuality.
  416.     if( includeHitTesting ) {
  417.         // Allocate a compression sequence and add source data for hittest mask
  418.         err = CompressSequenceBegin(&seq, GetGWorldPixMap(gwPrev), nil, nil, nil, kCompressDepth, kAnimationCodecType, 
  419.                                             anyCodec, codecLosslessQuality, codecLosslessQuality, 2, nil, 0, desc);
  420.  
  421.         // with hit testing, we have to add a data source to hold the mask data
  422.         err = CDSequenceNewDataSource(seq, &mapSource, kRecoProcHitTestingImageType, 1, (Handle)gwMapDesc, nil, nil);
  423.         if (err) goto bail;
  424.  
  425.         err = CDSequenceSetSourceData(mapSource, GetPixBaseAddr(GetGWorldPixMap(gwMap)), (**gwMapDesc).dataSize);
  426.         if (err) goto bail;
  427.  
  428.         // What's the maximum size the compressed data could be--including hit-test data?
  429.         err = GetCSequenceMaxCompressionSize(seq, GetGWorldPixMap(gwPrev), &dataSize);
  430.     }
  431.     else
  432.     {    // not hit-testing so we only need the image buffer
  433.         err = CompressSequenceBegin( &seq, GetGWorldPixMap(gwImage), nil, &bounds, nil, kCompressDepth, kAnimationCodecType, 0, 
  434.                                     codecLosslessQuality, codecLosslessQuality, 2, nil, 0, desc );
  435.         if(err) goto bail;
  436.         
  437.         // What's the maximum size the compressed data could be?
  438.         err = GetCSequenceMaxCompressionSize(seq, GetGWorldPixMap(gwImage), &dataSize);
  439.     }
  440.     if (err) goto bail;
  441.     
  442.  
  443.     data = NewPtr( dataSize );
  444.     if( (err = MemError()) != noErr) goto bail;
  445.     
  446.     if( includeHitTesting /* with or without transparency */ ) {
  447.         // With hittesting, we use two buffers. Actually we don't have to but do so to show how it can be
  448.         // done. Also, this code was based upon some older code that did.
  449.         
  450.         
  451.         // compress the GWorld painted with the keyColor exclusively
  452.         err = CompressSequenceFrame( seq, GetGWorldPixMap(gwPrev), nil, 0, data, &dataSize, &similarity, nil );
  453.         if ( err ) goto bail;
  454.  
  455.         err = SetCSequencePrev(seq, GetGWorldPixMap(gwPrev), nil);
  456.         if (err) goto bail;
  457.  
  458.         // draw the image into the GWorld over area painted with keyColor so that if picture is transparent already
  459.         // areas it doesn't paint will be in the key color
  460.         SetGWorld( gwImage, nil );
  461.         
  462.         GetBackColor( &saveBackColor );
  463.         if( keyColor )
  464.             RGBBackColor( keyColor );
  465.             
  466.             EraseRect( &bounds );
  467.         
  468.         RGBBackColor( &saveBackColor );
  469.     
  470.         err = drawProc( kRecoProcDrawMsg, &bounds, gwImage, kRecoProcOriginalImageType, drawProcRefcon );
  471.         if(err) goto bail;
  472.  
  473.         // now compress the GWorld holding the image drawn on top of the keyColor
  474.         err = CompressSequenceFrame(seq, GetGWorldPixMap(gwImage), nil, 0, data, &dataSize, &similarity, nil);
  475.         if (err) goto bail;
  476.         
  477.         // At this point, data points to the image data for just the difference between the two (thus generating transparency) 
  478.         // Also, hit testing data is contained in the image data if it was specified.
  479.     }
  480.     else if( includeTransparency ) {
  481.         // For transparency case without hittesting, we get by with only using a single buffer so we special case the
  482.         // code here. This is also for clarity.
  483.     
  484.         // compress the GWorld painted with the keyColor exclusively
  485.         err = CompressSequenceFrame( seq, GetGWorldPixMap(gwImage), nil, codecFlagUpdatePrevious, data, &dataSize, &similarity, nil );
  486.         if ( err ) goto bail;
  487.  
  488.         // draw the image into the GWorld over area painted with keyColor so that if picture is transparent already
  489.         // areas it doesn't paint will be in the key color
  490.         SetGWorld( gwImage, nil );
  491.         
  492.         GetBackColor( &saveBackColor );
  493.         if( keyColor )
  494.             RGBBackColor( keyColor );
  495.             
  496.             EraseRect( &bounds );
  497.         
  498.         RGBBackColor( &saveBackColor );
  499.     
  500.         err = drawProc( kRecoProcDrawMsg, &bounds, gwImage, kRecoProcOriginalImageType, drawProcRefcon );
  501.         if(err) goto bail;
  502.  
  503.         // now compress the GWorld holding the image drawn on top of the keyColor
  504.         err = CompressSequenceFrame(seq, GetGWorldPixMap(gwImage), nil, codecFlagUpdatePrevious, data, &dataSize, &similarity, nil);
  505.         if (err) goto bail;
  506.         
  507.         // At this point, data points to the image data for just the difference between the two (thus generating transparency) 
  508.         // Also, hit testing data is contained in the image data if it was specified.
  509.     }
  510.     else
  511.     {
  512.         SetGWorld( gwImage, nil );
  513.  
  514.         // draw the image into the GWorld
  515.         err = drawProc( kRecoProcDrawMsg, &bounds, gwImage, kRecoProcOriginalImageType, drawProcRefcon );
  516.         if(err) goto bail;
  517.  
  518.         // compress the GWorld containing the image painted on white
  519.         err = CompressSequenceFrame( seq, GetGWorldPixMap(gwImage), nil, 0, data, &dataSize, &similarity, nil );
  520.         if ( err ) goto bail;
  521.         
  522.         // At this point, data points to the image data for just the image, newly compressed. Also, hit testing data is contained
  523.         // in the image data if it was specified.
  524.     }
  525.     
  526.     CDSequenceEnd( seq );
  527.     seq = 0;
  528.     
  529.     // free the GWorlds and drop references so we have more memory for PtrToHand
  530.     if( gwImage )    DisposeGWorld( gwImage );
  531.     gwImage = nil;
  532.     if( gwMap )    DisposeGWorld( gwMap );
  533.     gwMap = nil;
  534.     if( gwPrev ) DisposeGWorld( gwPrev );
  535.     gwPrev = nil;
  536.     
  537.     err = PtrToHand( data, imageData, dataSize );
  538.     if ( err ) goto bail;
  539.     
  540.     *idh = desc;
  541.     desc = nil;                // forget about this name for ImageDescriptionHandle so dispose below doesn't catch it
  542.     
  543. bail:
  544.     // tell callback to dispose of anything it allocated. We pass 'err ' in portType if an error occurred
  545.     drawProc( kRecoProcDisposeMsg, nil, nil, err ? FOUR_CHAR_CODE('err ') : 0, drawProcRefcon );
  546.     
  547.     CDSequenceEnd( seq );
  548.     SetGWorld( savePort, saveDevice );
  549.     
  550.     if(gwImage)        DisposeGWorld( gwImage );
  551.     if(gwMap )        DisposeGWorld( gwMap );
  552.     if(gwPrev )        DisposeGWorld( gwPrev );
  553.     if(desc)         DisposeHandle((Handle) desc );
  554.     if(gwMapDesc)    DisposeHandle((Handle) gwMapDesc );
  555.     if(data)        DisposePtr( data );
  556.         
  557.     return err;
  558. }
  559.  
  560.  
  561. /*
  562.     myPictureCompressDrawProc
  563.     
  564.     Helper routine to be used with RecompressWithTransparencyFromProc to compress QuickDraw Pictures.
  565.  */
  566.  
  567. static PASCAL_RTN OSErr myPictureCompressDrawProc( short message, Rect * bounds, GWorldPtr drawingPort, OSType drawingImageType, void * refcon )
  568. {
  569. #if TARGET_OS_MAC
  570. #pragma unused(drawingPort)
  571. #endif
  572.     OSErr err = noErr;
  573.     PictureCompressProcData * data = refcon;
  574.     Rect r;
  575.     
  576.     switch( message ) {
  577.         case kRecoProcInitMsg:
  578.             break;
  579.             
  580.         case kRecoProcDisposeMsg:
  581.             break;
  582.             
  583.         case kRecoProcGetBoundsMsg:
  584.             r = (**data->picture).picFrame;
  585.             
  586.             r.left = EndianS16_BtoN(r.left);
  587.             r.top = EndianS16_BtoN(r.top);
  588.             r.bottom = EndianS16_BtoN(r.bottom);
  589.             r.right = EndianS16_BtoN(r.right);
  590.             
  591.             MacOffsetRect(&r, (short)-r.left, (short)-r.top );
  592.             
  593.             *bounds = r;
  594.             break;
  595.             
  596.         case kRecoProcDrawMsg:
  597.             r = (**data->picture).picFrame;
  598.             
  599.             r.left = EndianS16_BtoN(r.left);
  600.             r.top = EndianS16_BtoN(r.top);
  601.             r.bottom = EndianS16_BtoN(r.bottom);
  602.             r.right = EndianS16_BtoN(r.right);
  603.  
  604.             MacOffsetRect( &r, (short)-r.left, (short)-r.top );
  605.  
  606.             if( kRecoProcOriginalImageType == drawingImageType )
  607.                 DrawPictureNoDither( data->picture, &r );
  608.             break;
  609.         default:
  610.             err = -1;
  611.     }
  612.  
  613.     return err;
  614. }    
  615.     
  616.  
  617. /*
  618.     myImageCompressDrawProc
  619.     
  620.     Helper routine to be used with RecompressWithTransparencyFromProc to compress QuickTime compressed image data.
  621.  */
  622. static PASCAL_RTN OSErr myImageCompressDrawProc( short message, Rect * bounds, GWorldPtr drawingPort, OSType drawingImageType, void * refcon )
  623. {
  624. #if TARGET_OS_MAC
  625. #pragma unused(drawingImageType)
  626. #endif
  627.  
  628.     OSErr err = noErr;
  629.     CompressedImageCompressProcData * data = refcon;
  630.     Rect r;
  631.     
  632.     switch( message ) {
  633.     case kRecoProcInitMsg:
  634.         break;
  635.     case kRecoProcDisposeMsg:
  636.         break;
  637.     case kRecoProcGetBoundsMsg:
  638.         r.left = r.top = 0;
  639.         r.right = (**data->imageDesc).width;
  640.         r.bottom = (**data->imageDesc).height;
  641.         
  642.         *bounds = r;
  643.         break;
  644.     case kRecoProcDrawMsg:
  645.         {
  646.             SignedByte saveState;
  647.             
  648.             r.left = r.top = 0;
  649.             r.right = (**data->imageDesc).width;
  650.             r.bottom = (**data->imageDesc).height;
  651.             
  652.             saveState = HGetState( data->imageData );
  653.             HLockHi( data->imageData );
  654.             
  655.             if( kRecoProcOriginalImageType == drawingImageType )
  656.                 err = DecompressImage( *data->imageData, data->imageDesc, GetGWorldPixMap(drawingPort), &r, &r, srcCopy, nil );
  657.             
  658.             HSetState( data->imageData, saveState );
  659.         }
  660.         break;
  661.     default:
  662.         err = -1;
  663.     }
  664.  
  665.     return err;
  666. }    
  667.  
  668.  
  669.  
  670. /*
  671.     RecompressCompressedImageWithTransparency
  672.     
  673.     Given an ImageDescriptionHandle and a handle to image data, generate new RLE compressed data
  674.     with optional hitTesting and transparency.
  675.  */
  676. OSErr RecompressCompressedImageWithTransparency( ImageDescriptionHandle originalDesc, Handle originalImageData,
  677.                                         RGBColor *keyColor, 
  678.                                         RgnHandle hitTestRegion,
  679.                                         ImageDescriptionHandle *idh, Handle * imageData )
  680. {
  681.     OSErr err = noErr;
  682.     CompressedImageCompressProcData params;
  683.     
  684.     params.imageDesc = originalDesc;
  685.     params.imageData = originalImageData;
  686.     
  687.     err = RecompressWithTransparencyFromProc( myImageCompressDrawProc, ¶ms, 
  688.                                         (Boolean)(hitTestRegion != nil), 
  689.                                         keyColor, 
  690.                                         hitTestRegion, 
  691.                                         idh, imageData );
  692.     
  693.     return err;
  694. }
  695.  
  696. /*
  697.     RecompressPictureWithTransparency
  698.     
  699.     Given a QuickDraw PicHandle, generate new RLE compressed data with optional hitTesting and transparency.
  700.  */
  701. OSErr RecompressPictureWithTransparency( PicHandle originalPicture,
  702.                                         RGBColor *keyColor, 
  703.                                         RgnHandle hitTestRegion,
  704.                                         ImageDescriptionHandle *idh, Handle * imageData )
  705. {
  706.     OSErr err = noErr;
  707.     PictureCompressProcData params;
  708.     
  709.     params.picture = originalPicture;
  710.     
  711.     err = RecompressWithTransparencyFromProc( myPictureCompressDrawProc, ¶ms, 
  712.                                         (Boolean)(hitTestRegion != nil), 
  713.                                         keyColor, 
  714.                                         hitTestRegion, 
  715.                                         idh, imageData );
  716.     
  717.     return err;
  718. }
  719.  
  720. /*
  721.     RecompressPictureFileWithTransparency
  722.     
  723.     Given a QuickDraw PICT file, generate new RLE compressed data with optional hitTesting and transparency.
  724.     This function uses GetCompressedImageFromPicture to do the actual work on the PicHandle retrieved from
  725.     the PICT file.
  726.  */
  727. OSErr RecompressPictureFileWithTransparency( FSSpec * spec, 
  728.                                         RGBColor *keyColor, 
  729.                                         RgnHandle hitTestRegion,
  730.                                         ImageDescriptionHandle *idh, Handle * imageData )
  731. {
  732.     OSErr         err = noErr;
  733.     short        sourceRefNum = 0;
  734.     PicHandle    picture = nil;
  735.     long        eof;
  736.     long        countBytes;
  737.     
  738.     *idh = nil;
  739.     *imageData = nil;    
  740.     
  741.     BailOSErr(FSpOpenDF( spec, fsRdPerm, &sourceRefNum ));
  742.     
  743.     BailOSErr(GetEOF( sourceRefNum, &eof ));
  744.     eof -= 512;
  745.     
  746.     BailOSErr(SetFPos( sourceRefNum, fsFromStart, 512 ));
  747.             
  748.     picture = (PicHandle) NewHandle(eof);
  749.     err = MemError();
  750.     BailOSErr(err);
  751.  
  752.     countBytes = eof;
  753.     HLock((Handle) picture);
  754.     BailOSErr( FSRead( sourceRefNum, &countBytes, *picture) );
  755.     HUnlock((Handle) picture);
  756.     
  757.     BailOSErr( RecompressPictureWithTransparency( picture,  keyColor, hitTestRegion,
  758.                                 idh, imageData ));
  759.                                 
  760. bail:
  761.     if ( picture )            DisposeHandle((Handle) picture );
  762.     if ( sourceRefNum )        FSClose( sourceRefNum );
  763.         
  764.     return err;
  765. }
  766.  
  767.